home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Telnet / NCSA / tn3270 2.4d7 source / NCSA⁄BYU TCP⁄IP / user.c < prev    next >
Text File  |  1991-06-27  |  16KB  |  724 lines

  1. /*
  2. *  USER.C
  3. *  Network library interface routines
  4. *  Generally called by the session layer
  5. *
  6. ****************************************************************************
  7. *                                                                          *
  8. *      part of:                                                            *
  9. *      TCP/IP kernel for NCSA Telnet                                       *
  10. *      by Tim Krauskopf                                                    *
  11. *                                                                          *
  12. *      National Center for Supercomputing Applications                     *
  13. *      152 Computing Applications Building                                 *
  14. *      605 E. Springfield Ave.                                             *
  15. *      Champaign, IL  61820                                                *
  16. *                                                                          *
  17. *    Copyright (c) 1987, Board of Trustees of the University of Illinois   *
  18. *                                                                          *
  19. ****************************************************************************
  20. *  Revisions:
  21. *  10/87  Initial source release, Tim Krauskopf
  22. *  2/88  typedef support for other compilers (TK)
  23. *
  24. */
  25. #define MASTERDEF 1
  26.  
  27. #include <stdio.h>
  28. #include <string.h>
  29.  
  30. #include <Events.h>
  31.  
  32. #include "protocol.h"
  33. #include "data.h"
  34. #include "dlayer.h"
  35. #include "mactools.h"
  36. #include "protinit.h"
  37. #include "tcp.h"
  38. #include "tools.h"
  39.  
  40. #define LOWWATER 600
  41.  
  42. /***************************************************************************/
  43. /*  netread
  44. *   Read from a connection buffer into a user buffer.  
  45. *   Returns number of bytes read, < 0 on error
  46. */
  47. int netread
  48.   (
  49.     int pnum,
  50.     void *buffer,
  51.     int n
  52.   )
  53.     int pnum,n;
  54.     char *buffer;
  55.     {
  56.     int howmany,i;
  57.     struct port *p;
  58.  
  59.     if (pnum < 0)            /* check validity */
  60.         return(-2);
  61.  
  62.     if (NULL == (p = portlist[pnum]))
  63.         return(-2);
  64.  
  65.     if (p->state != SEST) {                 /* foreign or netclose */
  66.         if (p->state == SCWAIT) {            /* ready for me to close my side? */
  67.             if (!p->in.contain) {
  68.                 p->tcpout.t.flags = TFIN | TACK;
  69.                 tcpsend(p,0);
  70.                 p->state = SLAST;
  71.                 return(-1);
  72.             }
  73.             /* else, still data to be read */
  74.         }
  75.         else
  76.             return(-1);
  77.     }
  78.  
  79.     howmany = dequeue(&p->in,buffer,n);            /* read from tcp buffer */
  80.  
  81.     i = p->in.size;                                /* how much before? */
  82.  
  83.     p->in.size += howmany;                        /* increment leftover room  */
  84.  
  85.     if (i < LOWWATER && p->in.size >= LOWWATER) /* we passed mark */
  86.         p->out.lasttime = 0L;
  87.  
  88.     if (p->in.contain)                            /* if still data to be read */
  89.         netputuev(CONCLASS,CONDATA,pnum);        /* don't forget it */
  90.  
  91.     return(howmany);
  92.  
  93. } /* netread */
  94.  
  95. /************************************************************************/
  96. /* netwrite
  97. *  write something into the output queue, netsleep routine will come
  98. *  around and send the data, etc.
  99. *
  100. */
  101. int netwrite
  102.   (
  103.     int pnum,
  104.     void *buffer,
  105.     int n
  106.   )
  107.     {
  108.     int nsent,before;
  109.     struct port *p;
  110.  
  111.     if (pnum < 0)
  112.         return(-2);
  113.  
  114.     p = portlist[pnum];
  115.  
  116.     if (p == NULL)
  117.         return(-2);
  118.  
  119.     if (p->state != SEST)            /* must be established connection */
  120.         return(-1);
  121.  
  122.     before = p->out.contain;
  123.  
  124.     nsent = enqueue(&p->out,buffer,n);
  125.  
  126.     if (!before)                    /* if this is something new, */
  127.         p->out.lasttime = 0L;        /* cause timeout to be true */
  128.  
  129.     return(nsent);
  130.  
  131. } /* netwrite */
  132.  
  133. /**************************************************************************/
  134. /*  netpush
  135. *   attempt to push the rest of the data from the queue
  136. *   and then return whether the queue is empty or not (0 = empty)
  137. *   returns the number of bytes in the queue.
  138. */
  139. int netpush
  140.   (
  141.     int pnum
  142.   )
  143.     {
  144.     struct port *p;
  145.  
  146.     if (pnum < 0)
  147.         return(-2);
  148.  
  149.     if (NULL == (p = portlist[pnum]))
  150.         return(-2);
  151.  
  152.     p->out.push = 1;
  153.  
  154.     return(p->out.contain);
  155.  
  156. } /* netpush */
  157.  
  158. /**************************************************************************/
  159. /*  netqlen
  160. *   return the number of bytes waiting to be read from the incoming queue.
  161. */
  162. netqlen(pnum)
  163.     int pnum;
  164.     {
  165.  
  166.     if (portlist[pnum] == NULL)
  167.         return(-2);
  168.  
  169.     return(portlist[pnum]->in.contain);
  170.  
  171. }
  172.  
  173. /**************************************************************************/
  174. /*  netroom()
  175. *    return how much room is available in output buffer for a connection
  176. */
  177. int netroom
  178.   (
  179.     int pnum
  180.   )
  181.     {
  182.  
  183.     if (portlist[pnum] == NULL || portlist[pnum]->state != SEST)
  184.         return(-2);
  185.  
  186.     return(WINDOWSIZE - portlist[pnum]->out.contain);
  187.  
  188. }
  189.  
  190. /**************************************************************************/
  191. /* netsegsize and neterrchange and netsetip and netgetip
  192. *
  193. *  set operating parameters to change them from the default values used.
  194. */
  195.  
  196. netsegsize(newsize)
  197.     int newsize;
  198.     {
  199.     int i;
  200.  
  201.     i = nnsegsize;
  202.     nnsegsize = newsize;
  203.  
  204.     return(i);
  205. }
  206.  
  207. netquench(newcredit)
  208.     int newcredit;
  209.     {
  210.     int i;
  211.  
  212.     i = nncredit;
  213.     nncredit = newcredit;
  214.  
  215.     return(i);
  216. }
  217.  
  218. void netarptime                    /* dlayer timeout in secs */ 
  219.   (
  220.     int t
  221.   )
  222.     {
  223.     nndto = t;
  224. }
  225.  
  226. void netsetip
  227.   (
  228.     unsigned char *st
  229.   )
  230.     {
  231. /*
  232. *  change all dependent locations relating to the IP number
  233. *  don't worry about open connections, they must be closed by higher layer
  234. */
  235.     movebytes(nnipnum,st,4);
  236.  
  237. /*    movebytes(arp.d.me,nnipnum,4);    this is a bug - not needed */
  238.  
  239.     movebytes(arp.spa,nnipnum,4);
  240.     movebytes(blankip.i.ipsource,nnipnum,4);
  241.     movebytes(ulist.tcps.source,nnipnum,4);
  242.     movebytes(ulist.udpout.i.ipsource,nnipnum,4);
  243.  
  244. }
  245.  
  246. void netgetip
  247.   (
  248.     unsigned char *st
  249.   )
  250.   {
  251.     movebytes(st,nnipnum,4);
  252.   }
  253.  
  254. void netsetmask
  255.   (
  256.     unsigned char *st
  257.   )
  258.   {
  259.     movebytes(nnmask,st,4);
  260.   }
  261.  
  262. void netgetmask
  263.   (
  264.     unsigned char *st
  265.   )
  266.     {
  267.     movebytes(st,nnmask,4);
  268. }
  269.  
  270. void netfromport            /* next "open" will use this port */
  271.   (
  272.     int16 port
  273.   )
  274.     {
  275.     nnfromport = port;
  276.  
  277. }
  278.  
  279. /**************************************************************************/
  280. /*  netest?
  281. *  is a particular session established yet?
  282. *  Returns 0 if the connection is in the established state.
  283. */
  284. int netest
  285.   (
  286.     int pn
  287.   )
  288.     {
  289.     struct port *p;
  290.  
  291.     if (pn < 0 || pn > NPORTS)
  292.         return(-2);
  293.  
  294.     if (NULL == (p = portlist[pn]))
  295.         return(-2);
  296.  
  297.     if (p->state == SEST)
  298.         return(0);
  299.  
  300.     else if (p->state == SCWAIT) {
  301.             if (!p->in.contain) {
  302.                 p->tcpout.t.flags = TFIN | TACK;
  303.                 tcpsend(p,0);
  304.                 p->state = SLAST;
  305.                 return(-1);
  306.             }
  307.             else 
  308.                 return(0);                /* still more data to be read */
  309.     }
  310.  
  311.     return(-1);
  312.  
  313. } /* netest */
  314.  
  315. /**************************************************************************/
  316. /*  netlisten
  317. *   Listen to a TCP port number and make the connection automatically when
  318. *   the SYN packet comes in.  The TCP layer will notify the higher layers
  319. *   with a CONOPEN event.  Save the port number returned to refer to this
  320. *   connection.
  321. *
  322. *   usage:   portnum = netlisten(service);
  323. *            int service;
  324. *
  325. */
  326. int netlisten
  327.   (
  328.     uint serv
  329.   )
  330.     {
  331.     int    pnum;
  332.     struct port *prt;
  333.     uint16 nn;
  334.  
  335.     pnum = makeport();
  336.  
  337.     if (pnum < 0)
  338.         return(-2);
  339.  
  340.     if (NULL == (prt = portlist[pnum]))
  341.         return(-2);
  342.  
  343.     prt->in.port = serv;
  344.     prt->out.port = 0;                        /* accept any outside port #*/
  345.     prt->in.lasttime = time(NULL);            /* set time we started */
  346.  
  347.     prt->state = SLISTEN;
  348.     prt->credit = 512;                        /* default value until changed */
  349.     prt->tcpout.i.protocol = PROTTCP;
  350.     prt->tcpout.t.source = intswap(serv);    /* set service here too */
  351.  
  352. /*
  353. *  install maximum segment size which will be sent out in the first
  354. *  ACK-SYN packet
  355. */
  356.     prt->tcpout.x.options[0] = 2;
  357.     prt->tcpout.x.options[1] = 4;
  358.     /* install maximum segment size */
  359.     nn = intswap(nnsegsize);
  360.     movebytes(&prt->tcpout.x.options[2],&nn,2);
  361.  
  362.     return(pnum);
  363. } /* netlisten */
  364.  
  365. /***********************************************************************/
  366. /*  netgetftp
  367. *  Provides the information that ftp needs to open a stream back to the
  368. *  originator of the command connection.  The other side's IP number
  369. *  and the port numbers to be used to calculate the default data connection
  370. *  number.  Returns values in an integer array for convenient use in 
  371. *  PORT commands.
  372. */
  373. void netgetftp
  374.   (
  375.     int a[],
  376.     int pnum
  377.   )
  378.     {
  379.     struct port *p;
  380.     uint i;
  381.  
  382.     p = portlist[pnum];
  383.  
  384.     a[0] = p->tcpout.i.ipdest[0];
  385.     a[1] = p->tcpout.i.ipdest[1];
  386.     a[2] = p->tcpout.i.ipdest[2];
  387.     a[3] = p->tcpout.i.ipdest[3];
  388.     i = intswap(p->tcpout.t.source);
  389.     a[4] = i >> 8;
  390.     a[5] = i & 255;
  391.     i = intswap(p->tcpout.t.dest);
  392.     a[6] = i >> 8;
  393.     a[7] = i & 255;
  394.  
  395. } /* netgetftp */
  396.  
  397. /**************************************************************************/
  398. /* netclose
  399. *  Do appropriate actions to return connection state to SCLOSED which
  400. *  enables the memory for that port to be reused.
  401. */
  402. int netclose
  403.   (
  404.     int pnum
  405.   )
  406.     {
  407.     struct port *p;
  408.  
  409.     if (pnum < 0 || pnum > NPORTS)            /* is a valid port? */
  410.         return(-1);
  411.  
  412.     if ((p = portlist[pnum]) != NULL) {            /* something there */
  413.         switch (p->state) {
  414.             case SLISTEN:                /* we don't care anymore */
  415.             case SSYNS:
  416.                 p->state = SCLOSED;
  417.                 break;
  418.             case SEST:                    /* must initiate close */
  419.                 /* send FIN */
  420.                 p->tcpout.t.flags = TACK | TFIN;
  421.                 tcpsend(p,0);
  422.                 p->state = SFW1;            /* wait for ACK of FIN */
  423.                 break;                        /* do nothing for now ?*/
  424.  
  425.             case SCWAIT:                    /* other side already closed */
  426.                 p->tcpout.t.flags = TFIN | TACK;
  427.                 tcpsend(p,0);
  428.                 p->state = SLAST;
  429.                 break;
  430.  
  431.             case STWAIT:                    /* time out yet? */
  432.                 if (portlist[pnum]->out.lasttime + WAITTIME < time(NULL)) 
  433.                     p->state = SCLOSED;
  434.                 break;
  435.  
  436.             case SLAST:                    /* five minute time out */
  437.                 if (portlist[pnum]->out.lasttime + LASTTIME < time(NULL)) 
  438.                     p->state = SCLOSED;
  439.                 break;
  440.             default:
  441.                 break;
  442.         }
  443.     }
  444.     else
  445.         return(1);
  446.     return(0);
  447. } /* netclose */
  448.  
  449. /**********************************************************************/
  450.  
  451. int doconnect
  452.   (
  453.     int pnum,
  454.     int service,
  455.     int mseg
  456.   )
  457.     {
  458.     uint16 seg;
  459.     struct port *p;
  460.  
  461.     p = portlist[pnum];
  462.  
  463.     p->tcpout.i.protocol = PROTTCP;                /* this will be TCP socket */
  464.     p->tcpout.t.dest = intswap(service);        /* for example, telnet=23 */
  465.     p->out.port = service;                        /* service is same as port num*/
  466.     p->tcpout.t.flags = TSYN;                    /* want to start up sequence */
  467.     p->tcpout.t.ack = 0;                        /* beginning has no ACK */
  468.  
  469.     p->state = SSYNS;                            /* syn sent */
  470. /*
  471. *  install maximum segment size which will be sent out in the first
  472. *  ACK-SYN packet
  473. */
  474.     p->tcpout.x.options[0] = 2;
  475.     p->tcpout.x.options[1] = 4;
  476.     /* install maximum segment size */
  477.     seg = intswap(mseg);
  478.     movebytes(&p->tcpout.x.options[2],&seg,2);
  479.  
  480.     p->tcpout.t.hlen=96;                    /* include one more word in hdr */
  481.     tcpsend(p,4);                            /* send opening volley */
  482.     p->tcpout.t.hlen=80;                    /* normal hdr len */
  483.  
  484. /*    savenxt = p->out.nxt; */
  485.     p->out.nxt += 1;                        /* ack should be for next byte */
  486.  
  487.     return(pnum);                            /* do not wait for connect */
  488. } /* doconnect */
  489.  
  490. /**************************************************************************/
  491. /*  netxopen
  492. *   Open a network socket for the user.
  493. *
  494. */
  495. int netxopen
  496.   (
  497.     uint8 *machine,
  498.     uint service,
  499.     uint rto,
  500.     uint mtu,
  501.     uint mseg,
  502.     uint mwin
  503.   )
  504.     {
  505.     struct port *p;
  506.     int pnum,ret,i;
  507.     uint8 *pc,*hiset;
  508.  
  509. /*
  510. *  check the IP number and don't allow broadcast addresses.
  511. *
  512. *  If the AND of the original and the mask does not change the value then
  513. *  the host portion is all zeros.
  514. *  If the OR of the original and the inverse mask does not change the value
  515. *  then the host portion is all ones.
  516. */
  517.     ret = 0;                        /* assume all are the same */
  518.     for (i=0; i<4; i++)
  519.         if (machine[i] != (machine[i] & nnmask[i]))
  520.             ret = 1;
  521.  
  522.     if (!ret) {                        /* if all are the same, reject broadcast addr */
  523.         nnerror(506);
  524.         return(-4);
  525.     }
  526.     
  527.     ret = 0;
  528.     for (i=0; i<4; i++) 
  529.         if (machine[i] != (uint8)(machine[i] | (~nnmask[i])))
  530.             ret = 1;
  531.         
  532.     if (!ret) {                        /* if all are the same, reject broadcast addr */
  533.         nnerror(506);
  534.         return(-4);
  535.     }
  536.  
  537.     netsleep(0);                    /* make sure no waiting packets */
  538.     pnum = makeport();
  539.  
  540.     if (pnum < 0)
  541.         return(-3);
  542.  
  543.     p = portlist[pnum];                /* create a new port */
  544. /*
  545. *  make a copy of the ip number that we are trying for
  546. */
  547.     movebytes(p->tcpout.i.ipdest,machine,4);
  548.     movebytes(p->tcps.dest,machine,4);        /* pseudo header needs it */
  549.  
  550. /*
  551. *  get the hardware address for that host, or use the one for the gateway
  552. *  all handled by 'netdlayer' by ARPs.
  553. */
  554.     pc = netdlayer(machine);                /* we have ether? */
  555.  
  556.     if (pc == NULL) {                        /* cannot connect to local machine */
  557.         nnerror(504);
  558.         return(-2);
  559.     }
  560.  
  561.     movebytes(p->tcpout.d.dest,pc,DADDLEN);        /* load it up */
  562.  
  563. /*
  564. *   Add in machine specific settings for performance tuning
  565. */
  566.     if (rto > MINRTO)
  567.         p->rto = rto;            /* starting retrans timeout */
  568.     if (mtu < TMAXSIZE)            /* largest packet space we have */
  569.         p->sendsize = mtu;        /* maximum transmit size for that computer */
  570.     if (mwin < WINDOWSIZE)        /* buffer size is the limit */
  571.         p->credit = mwin;        /* most data that we can receive at once */
  572.  
  573. #ifdef MAC
  574.     if (nnemac) {
  575. #endif
  576. /*
  577. *   quick check to see if someone else is using your IP number
  578. *   Some boards receive their own broadcasts and cannot use this check.
  579. *   The Mac will only use this check if it is using EtherTalk.
  580. */
  581.         i = cachelook(nnipnum,0,0);                /* don't bother to ARP */
  582.         if (i >= 0)    {                /* if it is not -1, we are in trouble */
  583.             hiset = (uint8 *)arpc[i].hrd;
  584.             pc = neterrstring(-1);
  585.             sprintf(pc,"Conflict with Ethernet hardware address: %2x:%2x:%2x:%2x:%2x:%2x",
  586.             hiset[0],hiset[1],hiset[2],hiset[3],hiset[4],hiset[5]);
  587.             nnerror(-1);
  588.             nnerror(102);
  589.             netclose(pnum);
  590.             return(-3);
  591.         }
  592. #ifdef MAC
  593.     }
  594. #endif
  595.  
  596. /*
  597. *  make the connection, if you can, we will get an event notification later
  598. *  if it connects.  Timeouts must be done at a higher layer.
  599. */
  600.     ret = doconnect(pnum,service,mseg);
  601.  
  602.     return(ret);
  603. } /* netxopen */
  604.  
  605. /**************************************************************************/
  606. /*  netopen
  607. *   Netopen is a cheap way to open a connection without looking up any
  608. *   machine information.  Uses suitable default values for everything.
  609. */
  610. netopen(s,tport)
  611.     unsigned char *s;
  612.     uint tport;
  613.     {
  614.  
  615.     return(netxopen(s,tport,MINRTO,TSENDSIZE,DEFSEG,DEFWINDOW));
  616. }
  617.  
  618. /*************************************************************************/
  619. /*  netopen2
  620. *   Send out repeat SYN on a connection which is not open yet
  621. *   Checks, and only sends one if needed.
  622. *   Returns 1 if the state is still SYNS and 0 if the connection has proceeded.
  623. *   The timing is all handled at a higher layer.
  624. */
  625. int netopen2
  626.   (
  627.     int pnum
  628.   )
  629.     {
  630.     struct port *p;
  631.  
  632.     if (pnum < 0 || pnum > NPORTS)
  633.         return(-1);
  634.     if (NULL == (p = portlist[pnum]))
  635.         return(-2);
  636.  
  637.     if (p->state != SSYNS)
  638.             return(0);                /* done our job */
  639. /*
  640. *  The connection has not proceeded to further states, try retransmission
  641. */
  642.  
  643.     p->out.nxt--;
  644.     p->tcpout.t.hlen=96;        /* include one more word in hdr */
  645.     tcpsend(p,4);                /* try sending again */
  646.     p->tcpout.t.hlen=80;            /* normal hdr len */
  647.     p->out.nxt++;
  648.  
  649.     return(1);
  650. } /* netopen2 */
  651.  
  652. /**************************************************************************/
  653. /*  netinit
  654. *   Calls all of the various initialization routines that set up queueing
  655. *   variables, static values, reads configuration files, etc.
  656. */
  657.  
  658. int netinit
  659.   (
  660.     void
  661.   )
  662.     {
  663.     int ret;
  664.  
  665. /*
  666. *   Initializes all buffers and hardware for data link layer.
  667. *   Machine/board dependent.
  668. */
  669.     ret = dlayerinit();
  670.  
  671.     if (ret) {
  672.         nnerror(101);
  673.         return(ret);
  674.     }
  675. /*
  676. *  initialize the template packets needed for transmission
  677. */
  678.     ret = protinit();
  679.  
  680.     return(ret);                /* set up empty packets */
  681. } /* netinit */
  682.  
  683. /*************************************************************************/
  684. /*  netshut
  685. *   Close all the connections and turn off the hardware.
  686. */
  687. void netshut
  688.   (
  689.     void
  690.   )
  691.   {
  692.     int i;
  693.  
  694.     for (i=0; i < NPORTS ; i++) 
  695.         if (portlist[i] != NULL)
  696.             netclose(i);
  697.  
  698.     netsleep(1);
  699.  
  700.     dlayershut();
  701.   }
  702.  
  703. /*************************************************************************/
  704. /* neteventinit
  705. *  load up the pointers for the event queue
  706. *  makes a circular list to follow, required for error messages
  707. */
  708. void neteventinit
  709.   (
  710.     void
  711.   )
  712.     {
  713.     int i;
  714.  
  715.     for (i=0; i < NEVENTS; i++)
  716.         nnq[i].next = i+1;
  717.  
  718.     nnq[NEVENTS-1].next = -1;
  719.  
  720.     nnefirst = 0;
  721.     nnelast = 0;
  722.     nnefree = 1;
  723. } /* neteventinit */
  724.